//
// Created by DengLibin on 2018/12/11 0011.
//
/**
 * 引用
引用(就是这个变量的一个别名,与地址无关,必须要先有变量,然后才有这个变量的引用)
1）引用作为其它变量的别名而存在，因此在一些场合可以代替指针
2）引用相对于指针来说具有更好的可读性和实用性
引用在C++中的内部实现是一个常指针
 千万不要返回局部对象的引用！千万不要返回指向局部对象的指针！
 */
#include <iostream>
using namespace std;
//通过引用修改变量的值（通过引用直接修改变量的值,不会分配内存来接收参数,没有压栈和出栈操作,效率高)
void chanage_i(int &i)
{
    cout <<&i<<endl; //和实际参数的地址一致
    i = 40;
}
//常量引用,防止修改
void const_reference(const int &i)
{
   // i = 20;
}
//数组的引用
void testArrReference()
{
    int a[10] = {1,3,43,4,4,5,6,6,8,7};
    //一维数组的引用
    int(&ra)[10] = a;
    int(&ra2)[10](a);
    cout << a << "," << ra <<","<<ra2<< endl;//000000000019F808,000000000019F808,000000000019F808 同一个地址
    ra[0] = 100;
    ra2[1] = 1000;
    for (int i = 0; i < 10; i++)
    {
        cout << *(a + i) << ",";
    }
    cout << endl;
    //二维数组的引用
    int b[2][5] = { 1,2,3,4,5,6,7,8,9,10};
    int(&rb)[2][5] = b;
    for (int i = 0; i < 2; i++)
    {
        for (int j = 0; j < 5; j++)
        {
            cout << *(*(rb + i)+j) << ",";//b是二级指针
        }

    }
    cout << endl;

}
//函数指针的引用
int jia(int a, int b)
{
    return a + b;
}
int jian(int a, int b)
{
    return a - b;
}
void tesFunReference()
{
    int(*fp)(int, int) = jia;//函数指针fp
    int c = fp(1, 3);//通过函数指针调用函数
    cout << c << endl; //4
    //函数指针引用
    int(*&rfp)(int, int) = fp;
    //改变函数指针的指向
    rfp = jian;
    int d = fp(1,3);
    cout << d << endl; //-2
}

//返回一个函数指针
int(*getFunPointer())(int, int) //返回的函数的函数返回值是int，参数为int,int
{
    return jian;
}
void testGetFunPointer()
{
    int(*jian)(int, int) = getFunPointer();//返回函数指针
    int a = jian(3,2);
    cout << a << endl; //1
}
//返回函数指针的引用
int(*&getFunPointerReference())(int, int)
{
    int(*p)(int, int) = jian; //函数指针

    return p;
}
void testGetFunPointerReferece()
{
    int(*&rp)(int, int) = getFunPointerReference();
    int c = rp(5,4);
    cout << c << endl; //1
}

//右值引用&&
void rightReference(){
    /**
     * 传统的c++引用（现在称为左值引用）使得标识符 关联到左值。左值是一个表示数据的表达式（如变量名或解除引用的指针）
     * 程序可以取其地址。
     *
     * 右值一般指的是表示式中的临时变量，在c++中临时变量在表达式结束后就被销毁了，
     * 之后程序就无法再引用这个变量了。但是c++11提供了一个方法，让我们可以引用这个临时变量。这个方法就是所谓的右值引用
     * 那么右值引用有什么用呢？避免内存copy！
     * 不同于其它语言，在c++里变量是值语义（在JAVA、Python变量是引用语义）。因此对于赋值操作意味着内存拷贝而不是简单的赋值指针。
     * 而右值引用的一个作用就是我们可以通过重新利用临时变量（右值）来避免无意义的内存copy
     *
     * c++11新增了右值引用，使用&&表示。右值引用可关联到右值。右值包括字面量、诸如x+y等表达式以及函数返回值（条件是函数返回的不是引用）
     *
     * C++11 中为了引入强大的右值引用，将右值的概念进行了进一步的划分，分为：纯右值、将亡值。
纯右值(prvalue, pure rvalue)，纯粹的右值，要么是纯粹的字面量，例如?10,?true；要么是求值结果相当于字面量或匿名临时对象，
     例如?1+2。非引用返回的临时变量、运算表达式产生的临时变量、原始字面量、Lambda 表达式都属于纯右值。
将亡值(xvalue, expiring value)，是 C++11 为了引入右值引用而提出的概念（因此在传统 C++中，纯右值和右值是统一个概念），也就是即将被销毁、却能够被移动的值。
将亡值可能稍有些难以理解，我们来看这样的代码：

std::vector<int> foo() {
    std::vector<int> temp = {1, 2, 3, 4};
    return temp;
}
std::vector<int> v = foo();
     在这样的代码中，函数?foo?的返回值?temp?在内部创建然后被赋值给?v，然而?v?获得这个对象时，会将整个 temp 拷贝一份，然后把?temp?销毁，如果这个?temp?非常大，
     这将造成大量额外的开销（这也就是传统 C++ 一直被诟病的问题）。在最后一行中，v?是左值、foo()?返回的值就是右值（也是纯右值）。
但是，v?可以被别的变量捕获到，而?foo()?产生的那个返回值作为一个临时值，一旦被?v?复制后，将立即被销毁，无法获取、也不能修改。
将亡值就定义了这样一种行为：临时的值能够被识别、同时又能够被移动。
     */

    int x = 10; //把10拷贝了一份到x变量中
    int y = 23;
    int &&r1 = 23; //指向23
    int &&r2 = x+y; //直接指向x+y的运算结果（而不是把运算结果拷贝一份），即使修改了x，y的值 r2也不变
    x = 3;
    cout <<r1<<endl; //23
    cout <<&r1<<endl; //0xa1fdd0
    r1 = 345;
    cout <<r1<<endl; //345
    cout <<&r1<<endl; //0xa1fdd0
    int * p = &r1;
    *p = 34;
    cout << *p <<endl; //34
    cout <<r2<<endl; //33
    cout <<&r2<<endl; //0xa1fdd0

    int &&r3 = std::move(x);
    cout << r3 << endl; //3
    cout << &r3 << endl; //0xa1fdbc
    cout << &x << endl; //0xa1fdbc
    r3 = 78;
    cout << r3 <<endl;//78
    cout << x <<endl;//78

}

void testRightReference(int && x){
    x  = 100;
}

int main4()
{
   /* int i = 20;
    cout <<&i<<endl;
    chanage_i(i);
    cout <<"i= "<<i<<endl;*/
   //rightReference();
   int b = 230;
   testRightReference(std::move(b));
   cout << b; // 100
    return 0;
}
